import { BlockType, BlockTypes, world } from "@minecraft/server";
import { GameComponent } from "@sapi-game/main";
import { Logger, RandomUtils } from "@sapi-game/utils";
import { colorIdMap } from "@sapi-game/utils/vanila-data";
import { PixelPartyPatterns } from "../pattern";
import { PixelPartyMainState } from "../states/mainState";

export class PixelPartyPatternManager extends GameComponent<PixelPartyMainState> {
    private logger = new Logger(this.constructor.name);
    //图案
    readonly pattern: number[][];
    readonly row: number;
    readonly col: number;
    //方块
    readonly wool: BlockType[] = [];
    readonly terracotta: BlockType[] = [];
    readonly concrete: BlockType[] = [];
    readonly glazed_terracotta: BlockType[] = [];
    readonly blocks = [
        this.wool,
        this.terracotta,
        this.concrete,
        this.glazed_terracotta,
    ];
    curBlocks: BlockType[] = this.blocks[0];
    retainColor: number = 0;

    constructor(state: PixelPartyMainState) {
        super(state);
        const span = this.context.map.volume.toVolume().getSpan();
        //x行,z列
        this.row = span.x;
        this.col = span.z;
        this.pattern = Array.from({ length: this.row }, () =>
            Array(this.col).fill(0)
        );
        this.genColoredBlockId();
    }

    /**提前生成带颜色的方块id */
    private genColoredBlockId() {
        for (let color of colorIdMap) {
            this.wool.push(BlockTypes.get(color + "_wool")!);
            this.terracotta.push(BlockTypes.get(color + "_terracotta")!);
            this.concrete.push(BlockTypes.get(color + "_concrete")!);
            if (color == "light_gray") {
                this.glazed_terracotta.push(
                    BlockTypes.get("silver_glazed_terracotta")!
                );
            } else {
                this.glazed_terracotta.push(
                    BlockTypes.get(color + "_glazed_terracotta")!
                );
            }
        }
    }

    override onAttach(): void {}

    /**生成图案 */
    genPattern() {
        const generator =
            PixelPartyPatterns[
                RandomUtils.intRange(0, PixelPartyPatterns.length)
            ];
        console.log(generator.name);
        generator(this.pattern, this.pattern.length, this.pattern[0].length);
    }

    /**设置pattern到游戏 */
    setBlocks() {
        this.curBlocks = this.blocks[RandomUtils.int(this.blocks.length)];
        try {
            this.setPattern();
        } catch (err) {
            this.logger.error("设置图案失败", err);
        }
    }

    /** 更新留存方块 */
    updateRetainColor() {
        const numRowSamples = Math.min(10, this.row);
        const numColSamples = Math.min(10, this.col);
        const stepRow = Math.floor(this.row / numRowSamples) || 1;
        const stepCol = Math.floor(this.col / numColSamples) || 1;

        const candidates = new Set<number>();

        for (let i = 0; i < this.row; i += stepRow) {
            for (let j = 0; j < this.col; j += stepCol) {
                const color = this.pattern[i][j];
                if (color >= 0 && color <= 15) candidates.add(color);
            }
        }

        const arr = Array.from(candidates);
        if (arr.length > 0) {
            this.retainColor = arr[RandomUtils.int(arr.length)];
        } else {
            this.retainColor = 0; // 兜底
        }
    }

    /**获取留存方块的ID */
    getRetainBlock() {
        return this.curBlocks[this.retainColor];
    }

    /**删除其它方块 */
    removeBlocks() {
        try {
            this.setPattern(this.retainColor);
        } catch (err) {
            this.logger.error("删除方块失败", err);
        }
    }

    /**把图案放到游戏中 */
    private setPattern(retainColor?: number) {
        const volume = this.context.map.volume.toVolume();
        const min = volume.getMin();
        const dim = world.getDimension(this.context.map.gameRegion.dimensionId);
        const blocks = this.curBlocks;
        const pos = { x: 0, y: min.y, z: 0 };
        const air = BlockTypes.get("air")!;
        for (let i = 0; i < this.row; i++) {
            pos.x = min.x + i;
            for (let j = 0; j < this.col; j++) {
                pos.z = min.z + j;
                const color = this.pattern[i][j];
                if (retainColor !== undefined && color !== retainColor) {
                    dim.setBlockType(pos, air);
                } else {
                    dim.setBlockType(pos, blocks[color]);
                }
            }
        }
    }
}
